/*
 * 
 * Copyright 2010 David H Pollack
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * 
 */

package com.dhpollack.rotogss.servlets;

import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedHashSet;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.dhpollack.rotogss.data.RotoGSSTeams;
import com.dhpollack.rotogss.data.RotoGSSUsers;
import com.dhpollack.rotogss.data.YahooGames;
import com.dhpollack.rotogss.data.YahooLeagueTeams;
import com.dhpollack.rotogss.data.YahooLeagues;
import com.dhpollack.rotogss.helper.PMF;
import com.dhpollack.rotogss.helper.XPATH;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

/**
 * @author davidpl
 *
 */
public class YahooParseGamesServlet extends HttpServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 375644898235645401L;

	private static XPath xPath = XPATH.get().newXPath();
	
	private PersistenceManager pm = PMF.get().getPersistenceManager();

	public void doPost(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
		
		log("Start ParseGames Servlet");
		
		String games_xml  = (String) req.getAttribute("rotogss.gamesxml");

		String user = req.getParameter("user");
		
		if(user == null) {
			log("No user set");
			return;
		}
		
		RotoGSSUsers rotogss_user;
		Key rotogss_userkey = new KeyFactory.Builder(RotoGSSUsers.class.getSimpleName(),user).getKey();
		try {
			rotogss_user = pm.getObjectById(RotoGSSUsers.class, rotogss_userkey);
			log("Found User: " + rotogss_user.getGoogleUserKey().getName());
			if(rotogss_user.getYahooTeamsTracked() == null) {
				log("TeamsTracking Set doesn't exist");
				rotogss_user.setYahooTeamsTracked(new LinkedHashSet<RotoGSSTeams>());
			}
		} catch(JDOObjectNotFoundException e) {
			log("No user found for " + user);
			log("Key used: " + rotogss_userkey.toString());
			return;
		}
		
		if(games_xml != null) {
			try {
				NodeList nodes = parseYahooXml(games_xml, "//games/game");
				for( int i = 0 ; i<nodes.getLength() ; i++) {
					YahooGames g = parseGamesNode(nodes.item(i));
					
					Transaction tx = pm.currentTransaction();
					try {
						pm.getObjectById(YahooGames.class, g.getGameKey());
						log("Using Old Entity");
					} catch(JDOObjectNotFoundException e) {
						log("Persisting New Entity");
						try {
							tx.begin();
							pm.makePersistent(g);
							tx.commit();
						} finally {
							if(tx.isActive()) {
								tx.rollback();
								log("A transation error occurred with Game entity");
							}
						}
					}


					Transaction tx2 = pm.currentTransaction();
					try {
						tx2.begin();

						NodeList user_league_nodes = parseYahooXml(nodes.item(i), "leagues/league");
						int team_count = user_league_nodes.getLength();
						XPathExpression xpath_league = xPath.compile("league_key");
						XPathExpression xpath_team = xPath.compile("teams/team/team_key");
						log("Found " + team_count + " teams for game " + g.getGameId());
						for(int k=0;k < team_count;k++) {
							String league_key_string = (String) xpath_league.evaluate(user_league_nodes.item(k), XPathConstants.STRING);
							String team_key_string = (String) xpath_team.evaluate(user_league_nodes.item(k), XPathConstants.STRING);
							Key rotogss_key = KeyFactory.createKey(rotogss_user.getGoogleUserKey()
																, RotoGSSTeams.class.getSimpleName()
																, team_key_string);
							Key yahoo_team_key = new KeyFactory.Builder(YahooGames.class.getSimpleName(), g.getGameId())
													 .addChild(YahooLeagues.class.getSimpleName(), league_key_string)
													 .addChild(YahooLeagueTeams.class.getSimpleName(), team_key_string)
													 .getKey();
							RotoGSSTeams team = new RotoGSSTeams();
							team.setKey(rotogss_key);
							team.setTeamKey(yahoo_team_key);
							team.setIsTracking(true);
							if(!rotogss_user.getYahooTeamsTracked().contains(team)) {
								log("Adding team key " + team.getTeamKey() + " to user");
								rotogss_user.addYahooTeamsTracked(team);
							}
						}
						
						if(!rotogss_user.getYahooGamesTracked().contains(g.getGameKey())) {
							log("Adding game key to user: " + g.getGameKey());
							rotogss_user.addYahooGamesTracked(g.getGameKey());
						} else {
							log(rotogss_user.getGoogleUserKey().getName()
								+ " already has "
								+ g.getGameKey()
								);
						}
						pm.makePersistentAll(rotogss_user);
						tx2.commit();
					} finally {
						if(tx2.isActive()) {
							tx2.rollback();
							log("A transaction error occured with the User entity");
						}
					}
				}
			} catch (XPathExpressionException e) {
				// TODO Auto-generated catch block
				log(e.toString());
				e.printStackTrace();
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				log(e.toString());
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				log(e.toString());
				e.printStackTrace();
			}
			
		} else {
			log("games_xml is null");
		}
		
		
	}
	
	private NodeList parseYahooXml(String xml, String expression)
	throws SAXException, IOException, ParserConfigurationException, XPathExpressionException {
		InputSource is = new InputSource(new StringReader(xml));
		Document response = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
		NodeList n = (NodeList)xPath.evaluate( expression , response, XPathConstants.NODESET);
		return n;
	}
	
	private NodeList parseYahooXml(Node node, String expression)
	throws XPathExpressionException {
		NodeList n = (NodeList)xPath.evaluate( expression , node, XPathConstants.NODESET);
		return n;
	}
	
	private YahooGames parseGamesNode(Node node)
	throws XPathExpressionException {

		//String game_key = (String)xPath.evaluate("game_key", node, XPathConstants.STRING);
		Integer game_id = Integer.parseInt((String)xPath.evaluate("game_id", node, XPathConstants.STRING));
		String game_name = (String)xPath.evaluate("name", node, XPathConstants.STRING);
		String game_code = (String)xPath.evaluate("code", node, XPathConstants.STRING);
		String game_type = (String)xPath.evaluate("type", node, XPathConstants.STRING);
		String game_url = (String)xPath.evaluate("url", node, XPathConstants.STRING);
		String game_season = (String)xPath.evaluate("season", node, XPathConstants.STRING);

		Key key = KeyFactory.createKey(YahooGames.class.getSimpleName(), game_id);
		
		YahooGames g = new YahooGames();
		g.setGameKey(key);
		g.setGameId(game_id);
		g.setName(game_name);
		g.setCode(game_code);
		g.setType(game_type);
		g.setUrl(game_url);
		g.setIsTracking(false);
		g.setSeason(game_season);

		return g;
	}

}
